<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.13"/>
<title>OpenCV: Motion Deblur Filter</title>
<link href="../../opencv.ico" rel="shortcut icon" type="image/x-icon" />
<link href="../../tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../jquery.js"></script>
<script type="text/javascript" src="../../dynsections.js"></script>
<script type="text/javascript" src="../../tutorial-utils.js"></script>
<link href="../../search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../search/searchdata.js"></script>
<script type="text/javascript" src="../../search/search.js"></script>
<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    extensions: ["tex2jax.js", "TeX/AMSmath.js", "TeX/AMSsymbols.js"],
    jax: ["input/TeX","output/HTML-CSS"],
});
//<![CDATA[
MathJax.Hub.Config(
{
  TeX: {
      Macros: {
          matTT: [ "\\[ \\left|\\begin{array}{ccc} #1 & #2 & #3\\\\ #4 & #5 & #6\\\\ #7 & #8 & #9 \\end{array}\\right| \\]", 9],
          fork: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ \\end{array} \\right.", 4],
          forkthree: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ #5 & \\mbox{#6}\\\\ \\end{array} \\right.", 6],
          forkfour: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ #5 & \\mbox{#6}\\\\ #7 & \\mbox{#8}\\\\ \\end{array} \\right.", 8],
          vecthree: ["\\begin{bmatrix} #1\\\\ #2\\\\ #3 \\end{bmatrix}", 3],
          vecthreethree: ["\\begin{bmatrix} #1 & #2 & #3\\\\ #4 & #5 & #6\\\\ #7 & #8 & #9 \\end{bmatrix}", 9],
          cameramatrix: ["#1 = \\begin{bmatrix} f_x & 0 & c_x\\\\ 0 & f_y & c_y\\\\ 0 & 0 & 1 \\end{bmatrix}", 1],
          distcoeffs: ["(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4[, \\tau_x, \\tau_y]]]]) \\text{ of 4, 5, 8, 12 or 14 elements}"],
          distcoeffsfisheye: ["(k_1, k_2, k_3, k_4)"],
          hdotsfor: ["\\dots", 1],
          mathbbm: ["\\mathbb{#1}", 1],
          bordermatrix: ["\\matrix{#1}", 1]
      }
  }
}
);
//]]>
</script><script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js"></script>
<link href="../../doxygen.css" rel="stylesheet" type="text/css" />
<link href="../../stylesheet.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<!--#include virtual="/google-search.html"-->
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  <td id="projectlogo"><img alt="Logo" src="../../opencv-logo-small.png"/></td>
  <td style="padding-left: 0.5em;">
   <div id="projectname">OpenCV
   &#160;<span id="projectnumber">4.5.2</span>
   </div>
   <div id="projectbrief">Open Source Computer Vision</div>
  </td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.13 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "../../search",false,'Search');
</script>
<script type="text/javascript" src="../../menudata.js"></script>
<script type="text/javascript" src="../../menu.js"></script>
<script type="text/javascript">
$(function() {
  initMenu('../../',true,false,'search.php','Search');
  $(document).ready(function() { init_search(); });
});
</script>
<div id="main-nav"></div>
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

<div id="nav-path" class="navpath">
  <ul>
<li class="navelem"><a class="el" href="../../d9/df8/tutorial_root.html">OpenCV Tutorials</a></li><li class="navelem"><a class="el" href="../../d7/da8/tutorial_table_of_content_imgproc.html">Image Processing (imgproc module)</a></li>  </ul>
</div>
</div><!-- top -->
<div class="header">
  <div class="headertitle">
<div class="title">Motion Deblur Filter </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p><b>Prev Tutorial:</b> <a class="el" href="../../de/d3c/tutorial_out_of_focus_deblur_filter.html">Out-of-focus Deblur Filter</a></p>
<p><b>Next Tutorial:</b> <a class="el" href="../../d4/d70/tutorial_anisotropic_image_segmentation_by_a_gst.html">Anisotropic image segmentation by a gradient structure tensor</a></p>
<table class="doxtable">
<tr>
<th align="right"></th><th align="left"></th></tr>
<tr>
<td align="right">Original author </td><td align="left">Karpushin Vladislav </td></tr>
<tr>
<td align="right">Compatibility </td><td align="left">OpenCV &gt;= 3.0 </td></tr>
</table>
<h2>Goal </h2>
<p>In this tutorial you will learn:</p>
<ul>
<li>what the PSF of a motion blur image is</li>
<li>how to restore a motion blur image</li>
</ul>
<h2>Theory </h2>
<p>For the degradation image model theory and the Wiener filter theory you can refer to the tutorial <a class="el" href="../../de/d3c/tutorial_out_of_focus_deblur_filter.html">Out-of-focus Deblur Filter</a>. On this page only a linear motion blur distortion is considered. The motion blur image on this page is a real world image. The blur was caused by a moving subject.</p>
<h3>What is the PSF of a motion blur image?</h3>
<p>The point spread function (PSF) of a linear motion blur distortion is a line segment. Such a PSF is specified by two parameters: \(LEN\) is the length of the blur and \(THETA\) is the angle of motion.</p>
<div class="image">
<img src="../../motion_psf.png" alt="motion_psf.png"/>
<div class="caption">
Point spread function of a linear motion blur distortion</div></div>
 <h3>How to restore a blurred image?</h3>
<p>On this page the Wiener filter is used as the restoration filter, for details you can refer to the tutorial <a class="el" href="../../de/d3c/tutorial_out_of_focus_deblur_filter.html">Out-of-focus Deblur Filter</a>. In order to synthesize the Wiener filter for a motion blur case, it needs to specify the signal-to-noise ratio ( \(SNR\)), \(LEN\) and \(THETA\) of the PSF.</p>
<h2>Source code </h2>
<p>You can find source code in the <code>samples/cpp/tutorial_code/ImgProc/motion_deblur_filter/motion_deblur_filter.cpp</code> of the OpenCV source code library.</p>
<div class="fragment"><div class="line"></div><div class="line"><span class="preprocessor">#include &lt;iostream&gt;</span></div><div class="line"><span class="preprocessor">#include &quot;<a class="code" href="../../d1/d4f/imgproc_2include_2opencv2_2imgproc_8hpp.html">opencv2/imgproc.hpp</a>&quot;</span></div><div class="line"><span class="preprocessor">#include &quot;<a class="code" href="../../d6/d87/imgcodecs_8hpp.html">opencv2/imgcodecs.hpp</a>&quot;</span></div><div class="line"></div><div class="line"><span class="keyword">using namespace </span><a class="code" href="../../d2/d75/namespacecv.html">cv</a>;</div><div class="line"><span class="keyword">using namespace </span>std;</div><div class="line"></div><div class="line"><span class="keywordtype">void</span> help();</div><div class="line"><span class="keywordtype">void</span> calcPSF(<a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; outputImg, <a class="code" href="../../d6/d50/classcv_1_1Size__.html">Size</a> filterSize, <span class="keywordtype">int</span> len, <span class="keywordtype">double</span> theta);</div><div class="line"><span class="keywordtype">void</span> fftshift(<span class="keyword">const</span> <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; inputImg, <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; outputImg);</div><div class="line"><span class="keywordtype">void</span> filter2DFreq(<span class="keyword">const</span> <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; inputImg, <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; outputImg, <span class="keyword">const</span> <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; H);</div><div class="line"><span class="keywordtype">void</span> calcWnrFilter(<span class="keyword">const</span> <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; input_h_PSF, <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; output_G, <span class="keywordtype">double</span> nsr);</div><div class="line"><span class="keywordtype">void</span> edgetaper(<span class="keyword">const</span> <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; inputImg, <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; outputImg, <span class="keywordtype">double</span> gamma = 5.0, <span class="keywordtype">double</span> beta = 0.2);</div><div class="line"></div><div class="line"><span class="keyword">const</span> <a class="code" href="../../dc/d84/group__core__basic.html#ga1f6634802eeadfd7245bc75cf3e216c2">String</a> keys =</div><div class="line"><span class="stringliteral">&quot;{help h usage ? |             | print this message             }&quot;</span></div><div class="line"><span class="stringliteral">&quot;{image          |input.png    | input image name               }&quot;</span></div><div class="line"><span class="stringliteral">&quot;{LEN            |125          | length of a motion             }&quot;</span></div><div class="line"><span class="stringliteral">&quot;{THETA          |0            | angle of a motion in degrees   }&quot;</span></div><div class="line"><span class="stringliteral">&quot;{SNR            |700          | signal to noise ratio          }&quot;</span></div><div class="line">;</div><div class="line"></div><div class="line"><span class="keywordtype">int</span> main(<span class="keywordtype">int</span> argc, <span class="keywordtype">char</span> *argv[])</div><div class="line">{</div><div class="line">    help();</div><div class="line">    <a class="code" href="../../d0/d2e/classcv_1_1CommandLineParser.html">CommandLineParser</a> parser(argc, argv, keys);</div><div class="line">    <span class="keywordflow">if</span> (parser.has(<span class="stringliteral">&quot;help&quot;</span>))</div><div class="line">    {</div><div class="line">        parser.printMessage();</div><div class="line">        <span class="keywordflow">return</span> 0;</div><div class="line">    }</div><div class="line"></div><div class="line">    <span class="keywordtype">int</span> LEN = parser.get&lt;<span class="keywordtype">int</span>&gt;(<span class="stringliteral">&quot;LEN&quot;</span>);</div><div class="line">    <span class="keywordtype">double</span> THETA = parser.get&lt;<span class="keywordtype">double</span>&gt;(<span class="stringliteral">&quot;THETA&quot;</span>);</div><div class="line">    <span class="keywordtype">int</span> snr = parser.get&lt;<span class="keywordtype">int</span>&gt;(<span class="stringliteral">&quot;SNR&quot;</span>);</div><div class="line">    <span class="keywordtype">string</span> strInFileName = parser.get&lt;<a class="code" href="../../dc/d84/group__core__basic.html#ga1f6634802eeadfd7245bc75cf3e216c2">String</a>&gt;(<span class="stringliteral">&quot;image&quot;</span>);</div><div class="line"></div><div class="line">    <span class="keywordflow">if</span> (!parser.check())</div><div class="line">    {</div><div class="line">        parser.printErrors();</div><div class="line">        <span class="keywordflow">return</span> 0;</div><div class="line">    }</div><div class="line"></div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> imgIn;</div><div class="line">    imgIn = <a class="code" href="../../d4/da8/group__imgcodecs.html#ga288b8b3da0892bd651fce07b3bbd3a56">imread</a>(strInFileName, <a class="code" href="../../d8/d6a/group__imgcodecs__flags.html#gga61d9b0126a3e57d9277ac48327799c80ae29981cfc153d3b0cef5c0daeedd2125">IMREAD_GRAYSCALE</a>);</div><div class="line">    <span class="keywordflow">if</span> (imgIn.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#abbec3525a852e77998aba034813fded4">empty</a>()) <span class="comment">//check whether the image is loaded or not</span></div><div class="line">    {</div><div class="line">        cout &lt;&lt; <span class="stringliteral">&quot;ERROR : Image cannot be loaded..!!&quot;</span> &lt;&lt; endl;</div><div class="line">        <span class="keywordflow">return</span> -1;</div><div class="line">    }</div><div class="line"></div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> imgOut;</div><div class="line"></div><div class="line">    <span class="comment">// it needs to process even image only</span></div><div class="line">    <a class="code" href="../../d2/d44/classcv_1_1Rect__.html">Rect</a> roi = <a class="code" href="../../dc/d84/group__core__basic.html#ga11d95de507098e90bad732b9345402e8">Rect</a>(0, 0, imgIn.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#aa3e5a47585c9ef6a0842556739155e3e">cols</a> &amp; -2, imgIn.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#abed816466c45234254d25bc59c31245e">rows</a> &amp; -2);</div><div class="line"></div><div class="line">    <span class="comment">//Hw calculation (start)</span></div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> Hw, h;</div><div class="line">    calcPSF(h, roi.<a class="code" href="../../d2/d44/classcv_1_1Rect__.html#ab0c92d80e25e22be48c0110c5200da1e">size</a>(), LEN, THETA);</div><div class="line">    calcWnrFilter(h, Hw, 1.0 / <span class="keywordtype">double</span>(snr));</div><div class="line">    <span class="comment">//Hw calculation (stop)</span></div><div class="line"></div><div class="line">    imgIn.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#adf88c60c5b4980e05bb556080916978b">convertTo</a>(imgIn, <a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga4a3def5d72b74bed31f5f8ab7676099c">CV_32F</a>);</div><div class="line">    edgetaper(imgIn, imgIn);</div><div class="line"></div><div class="line">    <span class="comment">// filtering (start)</span></div><div class="line">    filter2DFreq(imgIn(roi), imgOut, Hw);</div><div class="line">    <span class="comment">// filtering (stop)</span></div><div class="line"><span class="comment"></span></div><div class="line">    imgOut.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#adf88c60c5b4980e05bb556080916978b">convertTo</a>(imgOut, <a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga32b18d904ee2b1731a9416a8eef67d06">CV_8U</a>);</div><div class="line">    <a class="code" href="../../dc/d84/group__core__basic.html#ga1b6a396a456c8b6c6e4afd8591560d80">normalize</a>(imgOut, imgOut, 0, 255, <a class="code" href="../../d2/de8/group__core__array.html#ggad12cefbcb5291cf958a85b4b67b6149fa9f0c1c342a18114d47b516a88e29822e">NORM_MINMAX</a>);</div><div class="line">    <a class="code" href="../../d4/da8/group__imgcodecs.html#gabbc7ef1aa2edfaa87772f1202d67e0ce">imwrite</a>(<span class="stringliteral">&quot;result.jpg&quot;</span>, imgOut);</div><div class="line">    <span class="keywordflow">return</span> 0;</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keywordtype">void</span> help()</div><div class="line">{</div><div class="line">    cout &lt;&lt; <span class="stringliteral">&quot;2018-08-14&quot;</span> &lt;&lt; endl;</div><div class="line">    cout &lt;&lt; <span class="stringliteral">&quot;Motion_deblur_v2&quot;</span> &lt;&lt; endl;</div><div class="line">    cout &lt;&lt; <span class="stringliteral">&quot;You will learn how to recover an image with motion blur distortion using a Wiener filter&quot;</span> &lt;&lt; endl;</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keywordtype">void</span> calcPSF(<a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; outputImg, <a class="code" href="../../d6/d50/classcv_1_1Size__.html">Size</a> filterSize, <span class="keywordtype">int</span> len, <span class="keywordtype">double</span> theta)</div><div class="line">{</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> h(filterSize, <a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga4a3def5d72b74bed31f5f8ab7676099c">CV_32F</a>, <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(0));</div><div class="line">    <a class="code" href="../../db/d4e/classcv_1_1Point__.html">Point</a> point(filterSize.<a class="code" href="../../d6/d50/classcv_1_1Size__.html#abfe0367b32c407ddccf5ddf92667c73d">width</a> / 2, filterSize.<a class="code" href="../../d6/d50/classcv_1_1Size__.html#a1d289dce6b5d8006a54f3ee0259fc545">height</a> / 2);</div><div class="line">    <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ga28b2267d35786f5f890ca167236cbc69">ellipse</a>(h, point, <a class="code" href="../../dc/d84/group__core__basic.html#ga346f563897249351a34549137c8532a0">Size</a>(0, <a class="code" href="../../db/de0/group__core__utils.html#ga085eca238176984a0b72df2818598d85">cvRound</a>(<span class="keywordtype">float</span>(len) / 2.0)), 90.0 - theta, 0, 360, <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(255), <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ggaf076ef45de481ac96e0ab3dc2c29a777a89c5f6beef080e6df347167f85e07b9e">FILLED</a>);</div><div class="line">    <a class="code" href="../../d1/da0/classcv_1_1Scalar__.html">Scalar</a> summa = <a class="code" href="../../d2/de8/group__core__array.html#ga716e10a2dd9e228e4d3c95818f106722">sum</a>(h);</div><div class="line">    outputImg = h / summa[0];</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keywordtype">void</span> fftshift(<span class="keyword">const</span> <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; inputImg, <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; outputImg)</div><div class="line">{</div><div class="line">    outputImg = inputImg.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#adff2ea98da45eae0833e73582dd4a660">clone</a>();</div><div class="line">    <span class="keywordtype">int</span> cx = outputImg.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#aa3e5a47585c9ef6a0842556739155e3e">cols</a> / 2;</div><div class="line">    <span class="keywordtype">int</span> cy = outputImg.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#abed816466c45234254d25bc59c31245e">rows</a> / 2;</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> q0(outputImg, <a class="code" href="../../dc/d84/group__core__basic.html#ga11d95de507098e90bad732b9345402e8">Rect</a>(0, 0, cx, cy));</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> q1(outputImg, <a class="code" href="../../dc/d84/group__core__basic.html#ga11d95de507098e90bad732b9345402e8">Rect</a>(cx, 0, cx, cy));</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> q2(outputImg, <a class="code" href="../../dc/d84/group__core__basic.html#ga11d95de507098e90bad732b9345402e8">Rect</a>(0, cy, cx, cy));</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> q3(outputImg, <a class="code" href="../../dc/d84/group__core__basic.html#ga11d95de507098e90bad732b9345402e8">Rect</a>(cx, cy, cx, cy));</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> tmp;</div><div class="line">    q0.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#a33fd5d125b4c302b0c9aa86980791a77">copyTo</a>(tmp);</div><div class="line">    q3.copyTo(q0);</div><div class="line">    tmp.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#a33fd5d125b4c302b0c9aa86980791a77">copyTo</a>(q3);</div><div class="line">    q1.copyTo(tmp);</div><div class="line">    q2.copyTo(q1);</div><div class="line">    tmp.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#a33fd5d125b4c302b0c9aa86980791a77">copyTo</a>(q2);</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keywordtype">void</span> filter2DFreq(<span class="keyword">const</span> <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; inputImg, <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; outputImg, <span class="keyword">const</span> <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; H)</div><div class="line">{</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> planes[2] = { <a class="code" href="../../df/dfc/classcv_1_1Mat__.html">Mat_&lt;float&gt;</a>(inputImg.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#adff2ea98da45eae0833e73582dd4a660">clone</a>()), <a class="code" href="../../d3/d63/classcv_1_1Mat.html#a0b57b6a326c8876d944d188a46e0f556">Mat::zeros</a>(inputImg.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#a146f8e8dda07d1365a575ab83d9828d1">size</a>(), <a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga4a3def5d72b74bed31f5f8ab7676099c">CV_32F</a>) };</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> complexI;</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#ga7d7b4d6c6ee504b30a20b1680029c7b4">merge</a>(planes, 2, complexI);</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#gadd6cf9baf2b8b704a11b5f04aaf4f39d">dft</a>(complexI, complexI, <a class="code" href="../../d2/de8/group__core__array.html#ggaf4dde112b483b38175621befedda1f1ca74746fb171aa4bfc08ace28d73f52375">DFT_SCALE</a>);</div><div class="line"></div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> planesH[2] = { <a class="code" href="../../df/dfc/classcv_1_1Mat__.html">Mat_&lt;float&gt;</a>(H.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#adff2ea98da45eae0833e73582dd4a660">clone</a>()), <a class="code" href="../../d3/d63/classcv_1_1Mat.html#a0b57b6a326c8876d944d188a46e0f556">Mat::zeros</a>(H.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#a146f8e8dda07d1365a575ab83d9828d1">size</a>(), <a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga4a3def5d72b74bed31f5f8ab7676099c">CV_32F</a>) };</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> complexH;</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#ga7d7b4d6c6ee504b30a20b1680029c7b4">merge</a>(planesH, 2, complexH);</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> complexIH;</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#ga3ab38646463c59bf0ce962a9d51db64f">mulSpectrums</a>(complexI, complexH, complexIH, 0);</div><div class="line"></div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#gaa708aa2d2e57a508f968eb0f69aa5ff1">idft</a>(complexIH, complexIH);</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#ga0547c7fed86152d7e9d0096029c8518a">split</a>(complexIH, planes);</div><div class="line">    outputImg = planes[0];</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keywordtype">void</span> calcWnrFilter(<span class="keyword">const</span> <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; input_h_PSF, <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; output_G, <span class="keywordtype">double</span> nsr)</div><div class="line">{</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> h_PSF_shifted;</div><div class="line">    fftshift(input_h_PSF, h_PSF_shifted);</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> planes[2] = { <a class="code" href="../../df/dfc/classcv_1_1Mat__.html">Mat_&lt;float&gt;</a>(h_PSF_shifted.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#adff2ea98da45eae0833e73582dd4a660">clone</a>()), <a class="code" href="../../d3/d63/classcv_1_1Mat.html#a0b57b6a326c8876d944d188a46e0f556">Mat::zeros</a>(h_PSF_shifted.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#a146f8e8dda07d1365a575ab83d9828d1">size</a>(), <a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga4a3def5d72b74bed31f5f8ab7676099c">CV_32F</a>) };</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> complexI;</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#ga7d7b4d6c6ee504b30a20b1680029c7b4">merge</a>(planes, 2, complexI);</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#gadd6cf9baf2b8b704a11b5f04aaf4f39d">dft</a>(complexI, complexI);</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#ga0547c7fed86152d7e9d0096029c8518a">split</a>(complexI, planes);</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> denom;</div><div class="line">    <a class="code" href="../../d7/dcc/group__core__utils__softfloat.html#ga8bc36646a43b82baa15f151a973fb0c5">pow</a>(<a class="code" href="../../d2/d75/namespacecv.html#af6df65b17fb11af6d34634b6dfa44683">abs</a>(planes[0]), 2, denom);</div><div class="line">    denom += nsr;</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#ga6db555d30115642fedae0cda05604874">divide</a>(planes[0], denom, output_G);</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keywordtype">void</span> edgetaper(<span class="keyword">const</span> <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; inputImg, <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a>&amp; outputImg, <span class="keywordtype">double</span> gamma, <span class="keywordtype">double</span> beta)</div><div class="line">{</div><div class="line">    <span class="keywordtype">int</span> Nx = inputImg.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#aa3e5a47585c9ef6a0842556739155e3e">cols</a>;</div><div class="line">    <span class="keywordtype">int</span> Ny = inputImg.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#abed816466c45234254d25bc59c31245e">rows</a>;</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> w1(1, Nx, <a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga4a3def5d72b74bed31f5f8ab7676099c">CV_32F</a>, <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(0));</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> w2(Ny, 1, <a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga4a3def5d72b74bed31f5f8ab7676099c">CV_32F</a>, <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(0));</div><div class="line"></div><div class="line">    <span class="keywordtype">float</span>* p1 = w1.ptr&lt;<span class="keywordtype">float</span>&gt;(0);</div><div class="line">    <span class="keywordtype">float</span>* p2 = w2.ptr&lt;<span class="keywordtype">float</span>&gt;(0);</div><div class="line">    <span class="keywordtype">float</span> dx = float(2.0 * CV_PI / Nx);</div><div class="line">    <span class="keywordtype">float</span> x = float(-CV_PI);</div><div class="line">    <span class="keywordflow">for</span> (<span class="keywordtype">int</span> i = 0; i &lt; Nx; i++)</div><div class="line">    {</div><div class="line">        p1[i] = float(0.5 * (<a class="code" href="../../d0/de1/group__core.html#ga1c3ad52668041ecd803d1c0fc0b643c8">tanh</a>((x + gamma / 2) / beta) - <a class="code" href="../../d0/de1/group__core.html#ga1c3ad52668041ecd803d1c0fc0b643c8">tanh</a>((x - gamma / 2) / beta)));</div><div class="line">        x += dx;</div><div class="line">    }</div><div class="line">    <span class="keywordtype">float</span> dy = float(2.0 * CV_PI / Ny);</div><div class="line">    <span class="keywordtype">float</span> y = float(-CV_PI);</div><div class="line">    <span class="keywordflow">for</span> (<span class="keywordtype">int</span> i = 0; i &lt; Ny; i++)</div><div class="line">    {</div><div class="line">        p2[i] = float(0.5 * (<a class="code" href="../../d0/de1/group__core.html#ga1c3ad52668041ecd803d1c0fc0b643c8">tanh</a>((y + gamma / 2) / beta) - <a class="code" href="../../d0/de1/group__core.html#ga1c3ad52668041ecd803d1c0fc0b643c8">tanh</a>((y - gamma / 2) / beta)));</div><div class="line">        y += dy;</div><div class="line">    }</div><div class="line">    <a class="code" href="../../d3/d63/classcv_1_1Mat.html">Mat</a> w = w2 * w1;</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#ga979d898a58d7f61c53003e162e7ad89f">multiply</a>(inputImg, w, outputImg);</div><div class="line">}</div></div><!-- fragment --><h2>Explanation </h2>
<p>A motion blur image recovering algorithm consists of PSF generation, Wiener filter generation and filtering a blurred image in a frequency domain: </p><div class="fragment"><div class="line">    <span class="comment">// it needs to process even image only</span></div><div class="line">    <a class="code" href="../../dc/d84/group__core__basic.html#ga11d95de507098e90bad732b9345402e8">Rect</a> roi = <a class="code" href="../../dc/d84/group__core__basic.html#ga11d95de507098e90bad732b9345402e8">Rect</a>(0, 0, imgIn.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#aa3e5a47585c9ef6a0842556739155e3e">cols</a> &amp; -2, imgIn.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#abed816466c45234254d25bc59c31245e">rows</a> &amp; -2);</div><div class="line"></div><div class="line">    <span class="comment">//Hw calculation (start)</span></div><div class="line">    Mat Hw, h;</div><div class="line">    calcPSF(h, roi.size(), LEN, THETA);</div><div class="line">    calcWnrFilter(h, Hw, 1.0 / <span class="keywordtype">double</span>(snr));</div><div class="line">    <span class="comment">//Hw calculation (stop)</span></div><div class="line"></div><div class="line">    imgIn.<a class="code" href="../../d3/d63/classcv_1_1Mat.html#adf88c60c5b4980e05bb556080916978b">convertTo</a>(imgIn, <a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga4a3def5d72b74bed31f5f8ab7676099c">CV_32F</a>);</div><div class="line">    edgetaper(imgIn, imgIn);</div><div class="line"></div><div class="line">    <span class="comment">// filtering (start)</span></div><div class="line">    filter2DFreq(imgIn(roi), imgOut, Hw);</div><div class="line">    <span class="comment">// filtering (stop)</span></div></div><!-- fragment --><p> A function calcPSF() forms a PSF according to input parameters \(LEN\) and \(THETA\) (in degrees): </p><div class="fragment"><div class="line"><span class="keywordtype">void</span> calcPSF(Mat&amp; outputImg, <a class="code" href="../../dc/d84/group__core__basic.html#ga346f563897249351a34549137c8532a0">Size</a> filterSize, <span class="keywordtype">int</span> len, <span class="keywordtype">double</span> theta)</div><div class="line">{</div><div class="line">    Mat h(filterSize, <a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga4a3def5d72b74bed31f5f8ab7676099c">CV_32F</a>, <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(0));</div><div class="line">    <a class="code" href="../../dc/d84/group__core__basic.html#ga1e83eafb2d26b3c93f09e8338bcab192">Point</a> point(filterSize.width / 2, filterSize.height / 2);</div><div class="line">    <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ga28b2267d35786f5f890ca167236cbc69">ellipse</a>(h, point, <a class="code" href="../../dc/d84/group__core__basic.html#ga346f563897249351a34549137c8532a0">Size</a>(0, <a class="code" href="../../db/de0/group__core__utils.html#ga085eca238176984a0b72df2818598d85">cvRound</a>(<span class="keywordtype">float</span>(len) / 2.0)), 90.0 - theta, 0, 360, <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(255), <a class="code" href="../../d6/d6e/group__imgproc__draw.html#ggaf076ef45de481ac96e0ab3dc2c29a777a89c5f6beef080e6df347167f85e07b9e">FILLED</a>);</div><div class="line">    <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a> summa = <a class="code" href="../../d2/de8/group__core__array.html#ga716e10a2dd9e228e4d3c95818f106722">sum</a>(h);</div><div class="line">    outputImg = h / summa[0];</div><div class="line">}</div></div><!-- fragment --><p> A function edgetaper() tapers the input image’s edges in order to reduce the ringing effect in a restored image: </p><div class="fragment"><div class="line"><span class="keywordtype">void</span> edgetaper(<span class="keyword">const</span> Mat&amp; inputImg, Mat&amp; outputImg, <span class="keywordtype">double</span> gamma, <span class="keywordtype">double</span> beta)</div><div class="line">{</div><div class="line">    <span class="keywordtype">int</span> Nx = inputImg.cols;</div><div class="line">    <span class="keywordtype">int</span> Ny = inputImg.rows;</div><div class="line">    Mat w1(1, Nx, <a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga4a3def5d72b74bed31f5f8ab7676099c">CV_32F</a>, <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(0));</div><div class="line">    Mat w2(Ny, 1, <a class="code" href="../../d1/d1b/group__core__hal__interface.html#ga4a3def5d72b74bed31f5f8ab7676099c">CV_32F</a>, <a class="code" href="../../dc/d84/group__core__basic.html#ga599fe92e910c027be274233eccad7beb">Scalar</a>(0));</div><div class="line"></div><div class="line">    <span class="keywordtype">float</span>* p1 = w1.ptr&lt;<span class="keywordtype">float</span>&gt;(0);</div><div class="line">    <span class="keywordtype">float</span>* p2 = w2.ptr&lt;<span class="keywordtype">float</span>&gt;(0);</div><div class="line">    <span class="keywordtype">float</span> dx = float(2.0 * CV_PI / Nx);</div><div class="line">    <span class="keywordtype">float</span> x = float(-CV_PI);</div><div class="line">    <span class="keywordflow">for</span> (<span class="keywordtype">int</span> i = 0; i &lt; Nx; i++)</div><div class="line">    {</div><div class="line">        p1[i] = float(0.5 * (<a class="code" href="../../d0/de1/group__core.html#ga1c3ad52668041ecd803d1c0fc0b643c8">tanh</a>((x + gamma / 2) / beta) - <a class="code" href="../../d0/de1/group__core.html#ga1c3ad52668041ecd803d1c0fc0b643c8">tanh</a>((x - gamma / 2) / beta)));</div><div class="line">        x += dx;</div><div class="line">    }</div><div class="line">    <span class="keywordtype">float</span> dy = float(2.0 * CV_PI / Ny);</div><div class="line">    <span class="keywordtype">float</span> y = float(-CV_PI);</div><div class="line">    <span class="keywordflow">for</span> (<span class="keywordtype">int</span> i = 0; i &lt; Ny; i++)</div><div class="line">    {</div><div class="line">        p2[i] = float(0.5 * (<a class="code" href="../../d0/de1/group__core.html#ga1c3ad52668041ecd803d1c0fc0b643c8">tanh</a>((y + gamma / 2) / beta) - <a class="code" href="../../d0/de1/group__core.html#ga1c3ad52668041ecd803d1c0fc0b643c8">tanh</a>((y - gamma / 2) / beta)));</div><div class="line">        y += dy;</div><div class="line">    }</div><div class="line">    Mat w = w2 * w1;</div><div class="line">    <a class="code" href="../../d2/de8/group__core__array.html#ga979d898a58d7f61c53003e162e7ad89f">multiply</a>(inputImg, w, outputImg);</div><div class="line">}</div></div><!-- fragment --><p> The functions calcWnrFilter(), fftshift() and filter2DFreq() realize an image filtration by a specified PSF in the frequency domain. The functions are copied from the tutorial <a class="el" href="../../de/d3c/tutorial_out_of_focus_deblur_filter.html">Out-of-focus Deblur Filter</a>.</p>
<h2>Result </h2>
<p>Below you can see the real world image with motion blur distortion. The license plate is not readable on both cars. The red markers show the car’s license plate location. </p><div class="image">
<img src="../../motion_original.jpg" alt="motion_original.jpg"/>
<div class="caption">
Motion blur image. The license plates are not readable</div></div>
<p>Below you can see the restoration result for the black car license plate. The result has been computed with \(LEN\) = 125, \(THETA\) = 0, \(SNR\) = 700. </p><div class="image">
<img src="../../black_car.jpg" alt="black_car.jpg"/>
<div class="caption">
The restored image of the black car license plate</div></div>
<p> Below you can see the restoration result for the white car license plate. The result has been computed with \(LEN\) = 78, \(THETA\) = 15, \(SNR\) = 300. </p><div class="image">
<img src="../../white_car.jpg" alt="white_car.jpg"/>
<div class="caption">
The restored image of the white car license plate</div></div>
<p> The values of \(SNR\), \(LEN\) and \(THETA\) were selected manually to give the best possible visual result. The \(THETA\) parameter coincides with the car’s moving direction, and the \(LEN\) parameter depends on the car’s moving speed. The result is not perfect, but at least it gives us a hint of the image’s content. With some effort, the car license plate is now readable.</p>
<dl class="section note"><dt>Note</dt><dd>The parameters \(LEN\) and \(THETA\) are the most important. You should adjust \(LEN\) and \(THETA\) first, then \(SNR\).</dd></dl>
<p>You can also find a quick video demonstration of a license plate recovering method <a href="https://youtu.be/xSrE0hdhb4o">YouTube</a>. </p><div align='center'><iframe title='Video' width='560' height='349' src='https://www.youtube.com/embed/xSrE0hdhb4o?rel=0' frameborder='0' align='middle' allowfullscreen></iframe></div> </div></div><!-- contents -->
<!-- HTML footer for doxygen 1.8.6-->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated on Fri Apr 2 2021 11:36:35 for OpenCV by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="../../doxygen.png" alt="doxygen"/>
</a> 1.8.13
</small></address>
<script type="text/javascript">
//<![CDATA[
addTutorialsButtons();
//]]>
</script>
</body>
</html>
